package com.mk.exnotice.aop;

import com.mk.exnotice.annotation.ExceptionListener;
import com.mk.exnotice.handler.ExceptionHandler;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;

@Slf4j
@Aspect
public class ExceptionNoticeAop {

    private ExceptionHandler exceptionHandler;

    public ExceptionNoticeAop(ExceptionHandler exceptionHandler) {
        this.exceptionHandler = exceptionHandler;
    }

    @AfterThrowing(value = "@within(listener)", throwing = "e", argNames = "listener,e")
    public void exceptionNotice(JoinPoint joinPoint, ExceptionListener listener, RuntimeException e) {
        handleException(e, joinPoint.getSignature().getName(), joinPoint.getArgs());
    }

    @AfterThrowing(value = "@annotation(listener)", throwing = "e", argNames = "listener,e")
    public void exceptionNoticeWithMethod(JoinPoint joinPoint, ExceptionListener listener, RuntimeException e) {
        handleException(e, joinPoint.getSignature().getName(), joinPoint.getArgs());
    }

    @Around("@annotation(com.mk.exnotice.annotation.ExceptionListener)  || @within(com.mk.exnotice.annotation.ExceptionListener)")
    public void exceptionNotice1(ProceedingJoinPoint pjp) throws Throwable{
        try {
            pjp.proceed();
        } catch (RuntimeException e) {
            Signature sig = pjp.getSignature();
            MethodSignature mSignature = (MethodSignature) sig;
            Object target = pjp.getTarget();
            Method currentMethod = target.getClass().getMethod(mSignature.getName(), mSignature.getParameterTypes());
            handleException(e, currentMethod.getName(), pjp.getArgs());
        }
    }


    private void handleException(RuntimeException exception, String methodName, Object[] args) {
        log.debug("出现异常：" + methodName + String.join(",", Arrays.stream(args).map(x -> x.toString()).toArray(String[]::new)));
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        String url = null;
        if (!ObjectUtils.isEmpty(requestAttributes)) {
            HttpServletRequest request = requestAttributes.getRequest();
            url = request.getRequestURL().toString();
        }
        exceptionHandler.createNotice(exception, url,methodName, args);
    }
}
